package jsj.open.lib.piccrop

import android.graphics.Point
import android.graphics.Rect
import android.util.Log

class PointsRect(r: Rect) {

    enum class PointPosition{
        LEFT_TOP,LEFT_BOTTOM,RIGHT_TOP,RIGHT_BOTTOM,
        LEFT_MIDDLE,TOP_MIDDLE,RIGHT_MIDDLE,BOTTOM_MIDDLE,BOUNDS,NONE
    }
    data class Wrapper(val position: PointPosition, var point: Point, var rect: Rect, var rectTouch:Rect)


    var lock16_9 = false
    var bounds:Rect
    var outlines:Rect = Rect()
    constructor():this(Rect(),)
    private var leftTopPoint:Point = Point()
    private var leftBottomPoint:Point = Point()
    private var rightTopPoint:Point = Point()
    private var rightBottomPoint:Point = Point()
    private var leftMiddlePoint:Point = Point()
    private var topMiddlePoint:Point = Point()
    private var rightMiddlePoint:Point = Point()
    private var bottomMiddlePoint:Point = Point()
    private var centerPoint:Point = Point()
    private var currentPostion = PointPosition.NONE
    private var maxWidth:Int = 0
    private var maxHeight:Int = 0
    var wrapperList:MutableList<Wrapper> = mutableListOf()
    val stokeWidth = 6
    init {
        bounds = r
        calculate()
        leftTopPoint.wrapPosition(PointPosition.LEFT_TOP)
        leftBottomPoint.wrapPosition(PointPosition.LEFT_BOTTOM)
        rightTopPoint.wrapPosition(PointPosition.RIGHT_TOP)
        rightBottomPoint.wrapPosition(PointPosition.RIGHT_BOTTOM)
        leftMiddlePoint.wrapPosition(PointPosition.LEFT_MIDDLE)
        topMiddlePoint.wrapPosition(PointPosition.TOP_MIDDLE)
        rightMiddlePoint.wrapPosition(PointPosition.RIGHT_MIDDLE)
        bottomMiddlePoint.wrapPosition(PointPosition.BOTTOM_MIDDLE)
    }

    fun pointsAll():List<Wrapper>{
        return mutableListOf<Wrapper>().apply {
            wrapperList.forEach {
                this.add(it)
            }
        }
    }

    private fun calculate() {
        bounds.left = Math.max(0,bounds.left)
        bounds.top = Math.max(0,bounds.top)
        bounds.right = Math.min(maxWidth,bounds.right)
        if(lock16_9){
            val w = bounds.right - bounds.left
            val h = w*9f/16f
            bounds.bottom = bounds.top + h.toInt()
            bounds.bottom = Math.min(maxHeight,bounds.bottom)
        }
        leftTopPoint.x = bounds.left
        leftTopPoint.y = bounds.top
        leftBottomPoint.x = bounds.left
        leftBottomPoint.y = bounds.bottom
        rightTopPoint.x = bounds.right
        rightTopPoint.y = bounds.top
        rightBottomPoint.x = bounds.right
        rightBottomPoint.y = bounds.bottom

        leftMiddlePoint.x = bounds.left
        leftMiddlePoint.y = bounds.top/2 + bounds.bottom/2
        topMiddlePoint.x = bounds.left/2 + bounds.right/2
        topMiddlePoint.y = bounds.top
        rightMiddlePoint.x = bounds.right
        rightMiddlePoint.y = bounds.top/2 + bounds.bottom/2
        bottomMiddlePoint.x = bounds.left/2 + bounds.right/2
        bottomMiddlePoint.y = bounds.bottom

        centerPoint.x = bounds.left/2 + bounds.right/2
        centerPoint.y = bounds.top/2 + bounds.bottom/2

        outlines.top = bounds.top +2
        outlines.left = bounds.left +2
        outlines.right = bounds.right +2
        outlines.bottom = bounds.bottom -2
        wrapperList.forEach {
            it.point.updateRect()
        }
    }

    fun set(r:Rect){
        bounds = r
        calculate()
    }
    fun setMax(maxW:Int,maxH:Int){
        maxWidth = maxW
        maxHeight = maxH
        calculate()
    }

    fun lockPosition(x: Int, y: Int): Boolean {
        pointsAll().forEach {
            if(it.rectTouch.contains(x,y))
            {
                Log.e(TAG, "触摸${it.position} -> ${it.rect}", )
                currentPostion = it.position
                return true
            }
        }
        if(bounds.contains(x,y)){
            currentPostion = PointPosition.BOUNDS
            Log.e(TAG, "触摸bounds", )
            return true
        }
        currentPostion = PointPosition.NONE
        return false
    }

    fun unlockPosition() {
        currentPostion = PointPosition.NONE
    }

    fun tryTrans(x: Int, y: Int) :Boolean{
        var dx = x
        var dy = y
        when(currentPostion){
            PointPosition.LEFT_TOP ->{
                bounds.left+=dx
                bounds.top+=dy
                bounds.left = Math.min(bounds.right-1,bounds.left)
                bounds.top = Math.min(bounds.bottom-1,bounds.top)
                calculate()
                return true
            }
            PointPosition.LEFT_BOTTOM ->{
                bounds.left+=dx
                bounds.bottom+=dy
                bounds.left = Math.min(bounds.right-1,bounds.left)
                bounds.bottom = Math.max(bounds.top+1,bounds.bottom)
                calculate()
                return true
            }
            PointPosition.RIGHT_TOP ->{
                bounds.right+=dx
                bounds.top+=dy
                bounds.top = Math.min(bounds.bottom-1,bounds.top)
                bounds.right = Math.max(bounds.left+1,bounds.right)
                calculate()
                return true
            }
            PointPosition.RIGHT_BOTTOM ->{
                bounds.right+=dx
                bounds.bottom+=dy
                bounds.right = Math.max(bounds.left+1,bounds.right)
                bounds.bottom = Math.max(bounds.top+1,bounds.bottom)
                calculate()
                return true
            }
            PointPosition.LEFT_MIDDLE ->{
                bounds.left+=dx
                bounds.left = Math.min(bounds.right-1,bounds.left)
                calculate()
                return true
            }
            PointPosition.TOP_MIDDLE ->{
                bounds.top+=dy
                bounds.top = Math.min(bounds.bottom-1,bounds.top)
                calculate()
                return true
            }
            PointPosition.RIGHT_MIDDLE ->{
                bounds.right+=dx
                bounds.right = Math.max(bounds.left+1,bounds.right)
                calculate()
                return true
            }
            PointPosition.BOTTOM_MIDDLE ->{
                bounds.bottom+=dy
                bounds.bottom = Math.max(bounds.top+1,bounds.bottom)
                calculate()
                return true
            }
            PointPosition.BOUNDS ->{
                if(bounds.left+dx < 0){
                    dx = 0
                }
                if(bounds.top+dy < 0){
                    dy = 0
                }
                if(bounds.right+dx > maxWidth){
                    dx = 0
                }
                if(bounds.bottom+dy > maxHeight){
                    dy = 0
                }
                bounds.left+=dx
                bounds.top+=dy
                bounds.right+=dx
                bounds.bottom+=dy
                calculate()
                return true
            }
            else ->{
                return false
            }
        }
    }



    private val touchRectScale = 5
    private fun Point.wrapPosition(pos: PointPosition){
        also {point ->
            wrapperList.add(
                Wrapper(pos,point, Rect(point.x-stokeWidth*2,point.y-stokeWidth*2,point.x+stokeWidth*2,point.y+stokeWidth*2),
                Rect(point.x-stokeWidth*touchRectScale,point.y-stokeWidth*touchRectScale,point.x+stokeWidth*touchRectScale,point.y+stokeWidth*touchRectScale))
            )
        }
    }
    private fun Point.updateRect(){
        wrapperList.firstOrNull {
            it.point == this
        }?.let {
            val point = it.point
            it.rect.set(point.x-stokeWidth*2,point.y-stokeWidth*2,point.x+stokeWidth*2,point.y+stokeWidth*2)
            it.rectTouch.set(point.x-stokeWidth*touchRectScale,point.y-stokeWidth*touchRectScale,point.x+stokeWidth*touchRectScale,point.y+stokeWidth*touchRectScale)
        }
    }
    companion object {
        private const val TAG = "PointsRect"
    }
}